#ifndef TERN_LANDMARK_H
#define TERN_LANDMARK_H

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/syscall.h>

const char* landmarks[TERN_LANDMARKS_NUM] = {
	// 0
	"pthread_mutex_init",
	"pthread_mutex_lock",
	"pthread_mutex_unlock",
	"pthread_mutex_trylock",
	"pthread_mutex_destroy",

	// 5
	"pthread_create",
	"pthread_join",
	"pthread_exit",

	// 8
	"pthread_cond_init",
	"pthread_cond_wait",
	"pthread_cond_timedwait",
	"pthread_cond_broadcast",
	"pthread_cond_signal",
	"pthread_cond_destroy",

	// 14
	"sleep",
	"usleep",
	"nanosleep",

	// 17
	"accept",
	"select",

	// 19
	"sigwait",										// For mysqld-5.1.35. Should not be sigwaitinfo, which is in uclibc library, thus can not be instumented.
	"ap_mpm_pod_check",				// Only for httpd.

	// 21
	START_TASK_LANDMARK,
	END_TASK_LANDMARK,

	// 23
	"pthread_barrier_init",
	"pthread_barrier_wait",
	"pthread_barrier_destroy",

	// 26
	"tern_init",
	"tern_symbolic", 
	"tern_before_landmark",
	"tern_after_landmark",
	"peak_cache_concrete_value",
	"is_cache_satisfied",
	"after_httpd_cache_insert",
	"isInputValidForApache",

	// 34
	"sem_post",
	"sem_wait",
	"sem_trywait",
	"sem_timedwait",

	// 38
	"syscall",

	// These functions are not real landmarks, but they are useful in our instrumentation.
	// 39
	"pthread_self",

	//40
	"pthread_rwlock_init",
	"pthread_rwlock_destroy",
	"pthread_rwlock_wrlock",
	"pthread_rwlock_rdlock",
	"pthread_rwlock_trywrlock",
	"pthread_rwlock_tryrdlock",
	"pthread_rwlock_unlock",
	
	//47
	"epoll_wait"			// for mysql-6.0.5-alpha.
};

// Utility function, define here, since it will be used by many modules, and these modules are not linked together.
int getLandmarkIndex(const char *landmark) {
	for (unsigned i = 0; i < (sizeof landmarks)/(sizeof landmarks[0]); i++) {
		if (strcmp(landmarks[i], landmark) == 0) {
			return (int)i;
		}
	}
	return -1;
}

// Ignoring a landmark at insertion, does not mean ignoring this landmark.
bool isIgnoredLandmarkAtInsertion(unsigned index) {
	return false;
}

bool isIgnoredLandmarkInReplay(unsigned index) {
	// Optimization in order to improve performance at replaying part.
	if (index == 19 ||											// sigwait
		index == 20 ||											// ap_mpm_pod_check
		
		index == 14 ||											// sleep
		index == 15 ||											// usleep
		index == 16 ||											// nanosleep
		
		index == 17 ||											// accept
		index == 18 ||											// select
		
		index == 38 ||											// syscall
		
		index == 26 ||											// tern_init

		index == 0 ||											// pthread_mutex_init		
		index == 8 ||											// pthread_cond_init
		index == 23 ||										// pthread_barrier_init

		index == 4 ||											// pthread_mutex_destroy
		index == 13 ||											// pthread_cond_destroy
		index == 25 ||											// pthread_barrier_destroy

		index == 40 ||											// pthread_rwlock_init
		index == 41 ||											// pthread_rwlock_destroy
		
		index == 39)												// pthread_self
		return true;
	return false;
}

__thread pid_t localTid = -1;
long cnt = 0;

pid_t gettid() {
/*	//cnt++;
	if (localTid == -1) {
		cnt++;
		localTid = syscall(SYS_gettid);
	}
	return localTid;*/
	return syscall(SYS_gettid);
}

long getCnt() {return cnt;}

#endif

